home *** CD-ROM | disk | FTP | other *** search
- #!/usr/skunk/bin/expect --
- # allow another user to share a shell (or other program) with you
- # See kibitz(1) man page for complete info.
- # Author: Don Libes, NIST
- # Date written: December 5, 1991
- # Date last editted: October 19, 1994
- # Version: 2.11
- exp_version -exit 5.0
-
- # if environment variable "EXPECT_PROMPT" exists, it is taken as a regular
- # expression which matches the end of your login prompt (but does not other-
- # wise occur while logging in).
-
- set prompt "(%|#|\\$) $" ;# default prompt
- set noproc 0
- set tty "" ;# default if no -tty flag
- set allow_escape 1 ;# allow escapes if true
- set escape_char \035 ;# control-right-bracket
- set escape_printable "^\]"
- set verbose 1 ;# if true, describe what kibitz is doing
-
- set kibitz "kibitz" ;# where kibitz lives if some unusual place.
- ;# this must end in "kibitz", but can have
- ;# things in front (like directory names).
- #set proxy "kibitz" ;# uncomment and set if you want kibitz to use
- ;# some other account on remote systems
-
- # The following code attempts to intuit whether cat buffers by default.
- # The -u flag is required on HPUX (8 and 9) and IBM AIX (3.2) systems.
- if [file exists $exp_exec_library/cat-buffers] {
- set catflags "-u"
- } else {
- set catflags ""
- }
- # If this fails, you can also force it by commenting in one of the following.
- # Or, you can use the -catu flag to the script.
- #set catflags ""
- #set catflags "-u"
-
- # Some flags must be passed onto the remote kibitz process. They are stored
- # in "kibitz_flags". Currently, they include -tty and -silent.
- set kibitz_flags ""
-
- while {[llength $argv]>0} {
- set flag [lindex $argv 0]
- switch -- $flag \
- "-noproc" {
- set noproc 1
- set argv [lrange $argv 1 end]
- } "-catu" {
- set catflags "-u"
- set argv [lrange $argv 1 end]
- } "-tty" {
- set tty [lindex $argv 1]
- set argv [lrange $argv 2 end]
- set kibitz_flags "$kibitz_flags -tty $tty"
- } "-noescape" {
- set allow_escape 0
- set argv [lrange $argv 1 end]
- } "-escape" {
- set escape_char [lindex $argv 1]
- set escape_printable $escape_char
- set argv [lrange $argv 2 end]
- } "-silent" {
- set verbose 0
- set argv [lrange $argv 1 end]
- set kibitz_flags "$kibitz_flags -silent"
- } "-proxy" {
- set proxy [lindex $argv 1]
- set argv [lrange $argv 2 end]
- } default {
- break
- }
- }
-
- if {([llength $argv]<1) && ($noproc==0)} {
- send_user "usage: kibitz \[args] user \[program ...]\n"
- send_user " or: kibitz \[args] user@host \[program ...]\n"
- exit
- }
-
- log_user 0
- set timeout -1
-
- set user [lindex $argv 0]
- if [string match -r $user] {
- send_user "KRUN" ;# this tells user_number 1 that we're running
- ;# and to prepare for possible error messages
- set user_number 3
- # need to check that it exists first!
- set user [lindex $argv 1]
- } else {
- set user_number [expr 1+(0==[string first - $user])]
- }
-
- # at this point, user_number and user are correctly determined
- # User who originated kibitz session has user_number == 1 on local machine.
- # User who is responding to kibitz has user_number == 2.
- # User who originated kibitz session has user_number == 3 on remote machine.
-
- # user 1 invokes kibitz as "kibitz user[@host]"
- # user 2 invokes kibitz as "kibitz -####" (some pid).
- # user 3 invokes kibitz as "kibitz -r user".
-
- # uncomment for debugging: leaves each user's session in a file: 1, 2 or 3
- #exec rm -f $user_number
- #exp_internal -f $user_number 0
-
- set user2_islocal 1 ;# assume local at first
-
- # later move inside following if $user_number == 1
- # return true if x is a prefix of xjunk, given that prefixes are only
- # valid at . delimiters
- # if !do_if0, skip the whole thing - this is here just to make caller simpler
- proc is_prefix {do_if0 x xjunk} {
- if 0!=$do_if0 {return 0}
- set split [split $xjunk .]
- for {set i [expr [llength $split]-1]} {$i>=0} {incr i -1} {
- if [string match $x [join [lrange $split 0 $i] .]] {return 1}
- }
- return 0
- }
-
- # get domainname. Unfortunately, on some systems, domainname(1)
- # returns NIS domainname which is not the internet domainname.
- proc domainname {} {
- # open pops stack upon failure
- set rc [catch {open /etc/resolv.conf r} file]
- if {$rc==0} {
- while {-1!=[gets $file buf]} {
- if 1==[scan $buf "domain %s" name] {
- close $file
- return $name
- }
- }
- close $file
- }
-
- # fall back to using domainname
- if {0==[catch {exec domainname} name]} {return $name}
-
- error "could not figure out domainname"
- }
-
- if $user_number==1 {
- if $noproc==0 {
- if [llength $argv]>1 {
- set pid [eval spawn [lrange $argv 1 end]]
- } else {
- set pid [spawn $env(SHELL)]
- }
- set shell $spawn_id
- }
-
- # is user2 remote?
- regexp (\[^@\]*)@*(.*) $user ignore tmp host
- set user $tmp
- if ![string match $host ""] {
- set h_rc [catch {exec hostname} hostname]
- set d_rc [catch domainname domainname]
-
- if {![is_prefix $h_rc $host $hostname]
- && ![is_prefix $d_rc $host $hostname.$domainname]} {
- set user2_islocal 0
- }
- }
-
- if !$user2_islocal {
- if $verbose {send_user "connecting to $host\n"}
-
- if ![info exists proxy] {
- proc whoami {} {
- global env
- if [info exists env(USER)] {return $env(USER)}
- if [info exists env(LOGNAME)] {return $env(LOGNAME)}
- if ![catch {exec whoami} user] {return $user}
- if ![catch {exec logname} user] {return $user}
- # error "can't figure out who you are!"
- }
- set proxy [whoami]
- }
- spawn rlogin $host -l $proxy -8
- set userin $spawn_id
- set userout $spawn_id
-
- catch {set prompt $env(EXPECT_PROMPT)}
-
- set timeout 120
- expect {
- assword: {
- stty -echo
- send_user "password (for $proxy) on $host: "
- set old_timeout $timeout; set timeout -1
- expect_user -re "(.*)\n"
- send_user "\n"
- set timeout $old_timeout
- send "$expect_out(1,string)\r"
- # bother resetting echo?
- exp_continue
- } incorrect* {
- send_user "invalid password or account\n"
- exit
- } "TERM = *) " {
- send "\r"
- exp_continue
- } timeout {
- send_user "connection to $host timed out\n"
- exit
- } eof {
- send_user "connection to host failed: $expect_out(buffer)"
- exit
- } -re $prompt
- }
- if $verbose {send_user "starting kibitz on $host\n"}
- # the kill protects user1 from receiving user3's
- # prompt if user2 exits via expect's exit.
- send "$kibitz $kibitz_flags -r $user;kill -9 $$\r"
-
- expect {
- -re "kibitz $kibitz_flags -r $user.*KRUN" {}
- -re "kibitz $kibitz_flags -r $user.*(kibitz\[^\r\]*)\r" {
- send_user "unable to start kibitz on $host: \"$expect_out(1,string)\"\n"
- send_user "try rlogin by hand followed by \"kibitz $user\"\n"
- exit
- }
- timeout {
- send_user "unable to start kibitz on $host: "
- set expect_out(buffer) "timed out"
- set timeout 0; expect -re .+
- send_user $expect_out(buffer)
- exit
- }
- }
- expect {
- -re ".*\n" {
- # pass back diagnostics
- # should really strip out extra cr
- send_user $expect_out(buffer)
- exp_continue
- }
- KABORT exit
- default exit
- KDATA
- }
- }
- }
-
- if $user_number==2 {
- set pid [string trimleft $user -]
- }
-
- set local_io [expr ($user_number==3)||$user2_islocal]
- if $local_io||($user_number==2) {
- if 0==[info exists pid] {set pid [pid]}
-
- set userinfile /tmp/exp0.$pid
- set useroutfile /tmp/exp1.$pid
- }
-
- proc prompt1 {} {
- return "kibitz[info level].[history nextid]> "
- }
-
- set esc_match {}
- if {$allow_escape} {
- set esc_match {
- $escape_char {
- send_user "\nto exit kibitz, enter: exit\n"
- send_user "to suspend kibitz, press appropriate job control sequence\n"
- send_user "to return to kibitzing, enter: return\n"
- interpreter
- send_user "returning to kibitz\n"
- }
- }
- }
-
- proc prompt1 {} {
- return "kibitz[info level].[history nextid]> "
- }
-
- set timeout -1
-
- # kibitzer executes following code
- if $user_number==2 {
- # for readability, swap variables
- set tmp $userinfile
- set userinfile $useroutfile
- set useroutfile $tmp
-
- if ![file readable $userinfile] {
- send_user "Eh? No one is asking you to kibitz.\n"
- exit -1
- }
- spawn -open [open "|cat $catflags < $userinfile" "r"]
- set userin $spawn_id
-
- spawn -open [open $useroutfile w]
- set userout $spawn_id
- # open will hang until other user's cat starts
-
- stty -echo raw
- if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"}
-
- # While user is reading message, try to delete other fifo
- catch {exec rm -f $userinfile}
-
- eval interact $esc_match \
- -output $userout \
- -input $userin
-
- exit
- }
-
- # only user_numbers 1 and 3 execute remaining code
-
- proc abort {} {
- global user_number
-
- # KABORT tells user_number 1 that user_number 3 has run into problems
- # and is exiting, and diagnostics have been returned already
- if $user_number==3 {send_user KABORT}
- exit
- }
-
- if $local_io {
- proc mkfifo {f} {
- if 0==[catch {exec mkfifo $f}] return ;# POSIX
- if 0==[catch {exec mknod $f p}] return
- # some systems put mknod in wierd places
- if 0==[catch {exec /usr/etc/mknod $f p}] return ;# Sun
- if 0==[catch {exec /etc/mknod $f p}] return ;# AIX, Cray
- puts "Couldn't figure out how to make a fifo - where is mknod?"
- abort
- }
-
- proc rmfifos {} {
- global userinfile useroutfile
- catch {exec rm -f $userinfile $useroutfile}
- }
-
- trap {rmfifos; exit} {SIGINT SIGQUIT}
-
- # create 2 fifos to communicate with other user
- mkfifo $userinfile
- mkfifo $useroutfile
- # make sure other user can access despite umask
- exec chmod 666 $userinfile $useroutfile
-
- if $verbose {send_user "asking $user to type: kibitz -$pid\n"}
-
- # can't use exec since write insists on being run from a tty!
- set rc [catch {
- system echo "Can we talk? Run: \"kibitz -$pid\"" | \
- /bin/write $user $tty
- }
- ]
- if $rc {rmfifos;abort}
-
- spawn -open [open $useroutfile w]
- set userout $spawn_id
- # open will hang until other user's cat starts
-
- spawn -open [open "|cat $catflags < $userinfile" "r"]
- set userin $spawn_id
- catch {exec rm $userinfile}
- }
-
- stty -echo raw
-
- if $user_number==3 {
- send_user "KDATA" ;# this tells user_number 1 to send data
-
- interact {
- -output $userout
- -input $userin eof {
- wait -i $userin
- return -tcl
- } -output $user_spawn_id
- }
- } else {
- if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"}
-
- if $noproc {
- interact {
- -output $userout
- -input $userin eof {wait -i $userin; return}
- -output $user_spawn_id
- }
- } else {
- eval interact $esc_match {
- -output $shell \
- -input $userin eof {
- wait -i $userin
- close -i $shell
- return
- } -output $shell \
- -input $shell -output "$user_spawn_id $userout"
- }
- wait -i $shell
- }
- }
-
- if $local_io rmfifos
-